package com.zys.sac.core.filter;

import com.zys.sac.core.constant.RequestStatus;
import com.zys.sac.core.helper.UrlRule;
import com.zys.sac.core.util.ServletResponseUtils;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证中心认证Filter基类，所有自定义认证过滤器可实现该抽象类
 *
 * Created by zhongjunkai on 2022/3/15.
 */
public abstract class SacCheckFilter extends OncePerRequestFilter {

    /**
     * 登录地址，由使用方自行实现，在plugin模块中已经抽象到配置文件中进行配置了
     *
     * @return
     */
    public abstract String loginPath();

    /**
     * 免认证的url，某些不需要权限体系进行拦截的可放在该集合中，支持ant格式
     */
    private List<AntPathRequestMatcher> avoidAntPathMatchers = new ArrayList(){{
        add(new AntPathRequestMatcher("/sso/**", "POST"));
        add(new AntPathRequestMatcher("/sso/**", "GET"));
    }};

    private List<AntPathRequestMatcher> onlyLoginPathMatchers = new ArrayList<>();

    private List<UrlRule> urlRules = new ArrayList<>();


    /**
     * 登出接口路径
     *
     * @return
     */
    public String logoutPath() {
        return "/logout";
    }

    /**
     * 登出成功后的回调路径
     *
     * @return
     */
    public String logoutSuccessUrl() {
        return "/logggg";
    }

    public List<AntPathRequestMatcher> onlyLoginPathMatchers() {
        return onlyLoginPathMatchers;
    }

    public void addOnlyLoginMatcher(AntPathRequestMatcher matcher) {
        onlyLoginPathMatchers.add(matcher);
    }

    public List<AntPathRequestMatcher> avoidMatchers() {
        return avoidAntPathMatchers;
    }

    public void addAvoidMatcher(AntPathRequestMatcher matcher) {
        avoidAntPathMatchers.add(matcher);
    }

    public List<UrlRule> urlRules() {
        return this.urlRules;
    }

    public void addUrlRule(UrlRule urlRule) {
        this.urlRules.add(urlRule);
    }

    protected abstract boolean doCheck(HttpServletRequest request, HttpServletResponse response) throws IOException;

    /**
     * 获取contextPath之后的URI
     *
     * @param request
     * @return
     */
    protected String getTargetPath(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return uri.substring(request.getContextPath().length());
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //处理登出
        if(getTargetPath(request).equals(logoutSuccessUrl())) {
            ServletResponseUtils.render(response, ServletResponseUtils.result(RequestStatus.LOGOUTSUCCESS.getCode(), RequestStatus.LOGOUTSUCCESS.getMsg()));
            return;
        }
        //处理登录
        if(StringUtils.hasText(loginPath()) && loginPath().equals(getTargetPath(request))) {
            filterChain.doFilter(request, response);
            return;
        }
        //因为有些url不需要做验证，这里做一层逻辑判断
        boolean matches = false;
        //检查当前路径是否在不需要验证的url列表中
        for(AntPathRequestMatcher matcher : avoidAntPathMatchers) {
            matches = matcher.matches(request);
            if(matches) {
                break;
            }
        }
        //如果不在免验证url列表中，则需要做check验证.
        if(!matches) {
            //根据处理结果决定是否执行后续的过滤器
            boolean checkResult = doCheck(request, response);
            if (checkResult) {
                filterChain.doFilter(request, response);
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }
}
